using FlyIL.Expression;
using FlyIL.Misc;
using FlyIL.Trace;
using System;
using System.Collections.Generic;
using System.Linq;
using static FlyIL.OperandMaker;
using static FlyIL.AssemblerRegisters;

namespace FlyIL.Optimizer;


/// <summary>
/// 
/// </summary>
public static class 表达式编译
{



    /// <summary>
    /// !!! 化简之前先 清理套娃 
    /// </summary>
    /// <param name="exp"></param>
    /// <param name="is64"></param>
    /// <param name="insts"></param>
    public static LinkedList<Inst> Compile(this Expr exp, bool is64, LinkedList<Inst> insts = null)
    {

        insts ??= new LinkedList<Inst>();

        Inst inst = new Inst(is64, 0, 0);
        inst.Opt = exp.Opt;

        if (inst.Opt == Opt.nop)
            return null;


        /// 如果左值是数字 ，则将左右值 调换
        if (exp.Left.IsNumeric())
        {
            var tmp = exp.Right;
            exp.Right = exp.Left;
            exp.Left = tmp;
        }
        if (exp.Left is Expr nl)
        {
            Compile(nl, is64, insts);
        }

        if (exp.Right is Expr nr)
        {
            Compile(nr, is64, insts);
        }


        inst.O1 = exp.FinalLeft<Operand>();

        if ((inst.Opt & Opt._Unary) > 0)
        {
            inst.OpsCount = 1;
        }
        else
        {
            inst.OpsCount = 2;
            if (exp.Right.IsNumeric())
                inst.O2 = Operand.Make((ulong)exp.Right.GetNumeric(), inst.O1.ByteSize);
            else
                inst.O2 = exp.FinalRight<Operand>();
        }


        insts.AddLast(inst);

        return insts;
    }





    /// <summary>
    /// 修改 表达式 到堆栈平衡 
    /// </summary>
    internal static void EquilibriumStack(this Context vcontext, Expr exp)
    {
        var nodes = exp.CollectDesc(5);
        nodes = nodes.OrderByDescending(o => o.Vip).ThenByDescending(o => o.SubIp).ToList();

        int sp_count = 0;
        foreach (var u in nodes)
        {
            sp_count += (int)u.SpVariety;
        }



        if (sp_count == 0)
            return;

        nodes.Reverse();

        /// 栈计数 小于0， 需要剔除 入栈 (push)
        if (sp_count < 0)
        {

            foreach (var u in nodes)
            {
                int sp_eff = (int)u.SpVariety;

                if (sp_eff < 0)
                {
                    if (u.Opt == Opt.push)
                    {
                        int offset = sp_eff - sp_count;
                        var op = Operand.Make(u.O1.ByteSize, vcontext.Is64 ? Rsp : Esp, offset);
                        exp.Replace(u, u.O1, op);


                    }

                }

                sp_count -= sp_eff;

                if (sp_count == 0)
                    break;
            }
        }



        return;

    }


    /// <summary>
    /// 验证这个 计算过程 是否独立（即没有数据被消费） ，如是则可以执行化简
    /// </summary>
    internal static bool IsExpIndependent(this Context vcontext, Expr exp)
    {

        var nodes = exp.CollectDesc(5);
        nodes = nodes.OrderBy(o => o.Vip).ThenBy(o => o.SubIp).ToList();

        List<OperandWrapper> associated = new List<OperandWrapper>();


        for (var it = nodes.First(); it != null && it != nodes.Last(); it = vcontext.GetNextIfExist(it))
        {
            var inst = it;

            /// 该语句是表达式的一部分
            if (nodes.Contains(it))
            {

                associated.Add(new OperandWrapper { ext = it, op = inst.O1 });
                if (inst.OpsCount == 2 && !inst.O2.IsImm)
                {
                    associated.Add(new OperandWrapper { ext = it, op = inst.O2 });
                }

                int eff = (int)inst.SpVariety;
                if (eff != 0)
                    associated.FixSp(eff);
            }

            /// 不属于表达式的语句，但是存在于 表达式的 汇编序列中 
            /// 先简单的认为 ， 出现即 非独立
            else
            {

                /// 如果该语句中 消费了 上面的变量 
                if (inst.OpsCount == 2 && associated.Any(o => o.op.Used(inst.O2)))
                    return false;
            }

            ;

        }

        return true;
    }



    /// <summary>
    /// 带有栈操作的编译，需要检查栈平衡
    /// </summary>
    /// <param name="node">目标结点</param>
    /// <param name="exp">原表达式</param>
    /// <param name="simp">简化后</param>
    internal static bool CompileWithStack(this Context vcontext, Inst node, Expr exp, Expr simp)
    {

        /// 如果化简后的深度， 大于原始的深度， 则无法编译 
        if (simp.Depth > exp.Depth)
            return false;

        var nodes = exp.CollectDesc(exp.Depth + 1);
        nodes = nodes.OrderBy(o => o.Vip).ThenBy(o => o.SubIp).ToList();

        if (!vcontext.IsInstsStackBalance(nodes[0], node))
            return false;


        /// 因为 Trace 天生会将 压栈替换掉 ， 因此 如果存在 多个压栈 ， 且 另一个如果 压入寄存器 ， 且 存在对其 计算， 则不能 对其化简 
        /// 因为 这会影响到 寄存器的值， 造成计算变形 
        for (int i = 1; i < nodes.Count; i++)
        {
            if (nodes[i].Opt == Opt.push && nodes[i].O1.IsRegister)
            {
                if (nodes[i].O1 != nodes[0].O1)
                {
                    var _ = exp.Find(o => o.Opt != Opt.nop && o.Left is Expr le && le.Left is Operand lo && lo == nodes[i].O1);
                    if (_ != null)
                        return false;
                }
            }
        }


        FlyIL.Container.LinkedList<Inst> list = new ();
        /// 表达式的 赋值对象 
        var op = node.O1;

        /// 用 pop 的操作数 ， 替代掉 左值 操作数 
        var ori = exp.FinalLeft<Operand>();
        if (ori != op)
        {
            simp.Replace(ori, op);
            list.AddFirst(new Inst(vcontext.Is64, 0, 0));
            list.Last.mov(op, ori);
        }
        /// 生成简化后的指令 
        var list2 = simp.Compile(vcontext.Is64);

        if (list2 != null)
            foreach (var u in list2)
                list.AddLast(u);

        if (list.Count > nodes.Count)
            return false;


        /// 此处已确定可以进行替换 
        /// 先针对 压栈 和弹栈操作 ， 进行修复 

        List<Inst> pp = new List<Inst>();
        foreach (var u in nodes)
        {
            if (u.SpVariety != 0)
                pp.Add(u);
        }
        vcontext.FixStackOffset(nodes[0], node, pp.ToArray());


        for (int i = 0; i < nodes.Count; i++)
        {
            vcontext.NOP(nodes[i]);

            if (list.Count >= i + 1)
                nodes[i].CopyFrom(list.ElementAt(i));
        }


        return true;


    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="node">目标结点</param>
    /// <param name="exp">原表达式</param>
    /// <param name="simp">简化后</param>
    internal static bool Compile(this Context vcontext, Inst node, Expr exp, Expr simp)
    {

        if (object.ReferenceEquals(exp, simp))
        {
            throw new ArgumentException("两个表达式 不得相同");
        }

        /// 如果化简后的深度， 大于原始的深度， 则无法编译 
        if (simp.Depth > exp.Depth)
            return false;

        /// 表达式的 赋值对象 
        var op = node.O1;

        var nodes = exp.CollectDesc(exp.Depth + 1);
        nodes = nodes.OrderBy(o => o.Vip).ThenBy(o => o.SubIp).ToList();

        /// 表达式中 ，被压栈的 操作数 
        var push_ops = exp.Collect<Operand>(o => o != null && (o).Opt == Opt.push);

        if (push_ops.Count > 2)
            return false;

        FlyIL.Container.LinkedList<Inst> list = new ();
        /// 用 pop 的操作数 ， 替代掉 左值 操作数 
        //var ori = exp.FinalLeft<Operand>();
        //if (ori != op)
        //{
        //    simp.Replace(ori, op);
        //    list.AddFirst(new Inst(vcontext.Is64, 0, 0));
        //    list.Last.mov(op, ori);
        //}

        Operand tmp_op;
        if (push_ops.Count == 2)
        {
            var ss = push_ops.ElementAt(1).ByteSize;
            if (ss == 1)
                tmp_op = OperandMaker._regs_[R0L];
            else if (ss == 2)
                tmp_op = OperandMaker._regs_[R0W];
            else if (ss == 4)
                tmp_op = OperandMaker._regs_[R0D];
            else
                tmp_op = OperandMaker._regs_[R0];

            simp.Replace(push_ops.ElementAt(1), tmp_op);

            /// 用 临时寄存器， 替代掉 第二个压栈的操作数  
            list.AddLast(new Inst(vcontext.Is64, 0, 0));
            list.Last.mov(tmp_op, push_ops.ElementAt(1));
        }

        int? spEffect = 0;
        foreach (var u in nodes)
        {
            spEffect += u.SpVariety;
        }

        if (!nodes.Contains(node))
            spEffect += node.SpVariety;


        /// 生成简化后的指令 
        var list2 = simp.Compile(vcontext.Is64);
        foreach (var u in list2)
            list.AddLast(u);

        if (spEffect != 0)
        {
            for (var uu = nodes.Last(); uu != null && uu != node; uu = vcontext.GetNextIfExist(uu))
            {
                if (uu.SpVariety + spEffect == 0)
                {
                    Operand f2 = vcontext.Is64 ? _qword_[Rsp] : _dword_[Esp];
                    Expr exp2 = vcontext.TraceStrict(uu.Previous, ref f2);
                    var nodes2 = exp2.CollectDesc(5);
                    foreach (var u in nodes2)
                    {
                        vcontext.NOP(u);
                    }

                    if (exp2.CalcDepth == 0)
                    {
                        uu.mov(f2, exp2.FinalLeft<Operand>());
                    }


                    break;
                }

            }

        }


        /// 要替换的节点不足以 ， 填入新的汇编代码
        if (nodes.Count < list.Count)
            throw new Exception();
        else
        {
            vcontext.NOP(node);
            foreach (var u in nodes)
            {
                vcontext.NOP(u);
            }
            for (int i = 0; i < list.Count; i++)
            {
                nodes[i].CopyFrom(list.ElementAt(i));
            }

            // vcontext.CheckDeadCode(nodes[0]);
        }


        return true;
    }

}
